﻿Imports System.IO
Imports System.Security.Principal
Imports System.Runtime.InteropServices
Imports Microsoft.Win32

Module MainModule
    Private mblnTarget As Boolean = False
    Private mblnOpenDir As Boolean = False
    Private mblnOpenProp As Boolean = False

    Function Main(args() As String) As Integer
        If args.Length = 0 Or args.Contains("/?") Then
            Console.WriteLine("Usage: checkpath [<options>] filename[.ext]")
            Console.WriteLine("Options:")
            Console.WriteLine("  /T If the file is a shortcut,then operate the shortcut's target file, otherwise operate the file directly;")
            Console.WriteLine("  /D /L Open the folder including the file;")
            Console.WriteLine("  /P Open the file's properties dialog;")
            Console.WriteLine("  /? Show this help;")
            Console.ReadKey()
            Return 0
        End If

        Dim strTarget = ""

        For Each strArg As String In args
            Select Case UCase(strArg)
                Case "/T"
                    mblnTarget = True
                Case "/D", "/L"
                    mblnOpenDir = True
                Case "/P"
                    mblnOpenProp = True
                Case Else
                    strTarget = strArg
            End Select
        Next

        Dim strPaths As String = Environment.GetEnvironmentVariable("Path")
        Dim arrPaths() As String = Split(".;" & strPaths, ";")

        Dim strPathExts As String = Environment.GetEnvironmentVariable("PATHEXT")
        Dim arrPathExts() As String = Split(strPathExts & ";", ";")

        Dim hsPaths As New HashSet(Of String)
        Dim col As New Collection

        Dim strFileName = strTarget
        If Path.GetExtension(strFileName) = "" Then
            strFileName &= ".EXE"
        End If

        Dim strFilePath = Registry.GetValue("HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" & strFileName, "", Nothing)
        If strFilePath IsNot Nothing Then
            If Not hsPaths.Contains(strFilePath) Then
                Deal(strFilePath)
                hsPaths.Add(strFilePath)
            End If
        End If

            If Path.GetExtension(strTarget) = "" Then
            For Each strPath As String In arrPaths
                If strPath = "" Then
                    Continue For
                End If

                For Each strPathExt As String In arrPathExts
                    Dim strTargetPath As String = Path.GetFullPath(Path.Combine(strPath, strTarget & strPathExt))
                    If File.Exists(strTargetPath) Then
                        Dim strKey As String = LCase(strTargetPath)
                        If Not hsPaths.Contains(strKey) Then
                            Deal(strTargetPath)
                            hsPaths.Add(strKey)
                        End If
                    End If
                Next
            Next
        Else
            For Each strPath As String In arrPaths
                If strPath = "" Then
                    Continue For
                End If

                Dim strTargetPath As String = Path.GetFullPath(Path.Combine(strPath, strTarget))
                If File.Exists(strTargetPath) Then
                    Dim strKey As String = LCase(strTargetPath)
                    If Not hsPaths.Contains(strKey) Then
                        Deal(strTargetPath)
                        hsPaths.Add(strKey)
                    End If
                End If
            Next
        End If

        Dim ret As Integer
        If hsPaths.Count = 0 Then
            Console.WriteLine("File not found.")
            ret = 1
        Else
            ret = 0
        End If

        '#If DEBUG Then
        Console.ReadKey(False)
        '#End If

        Return ret
    End Function

    Private Sub Deal(strTargetPath As String)
        Console.Write(strTargetPath)

        Dim strShortcutTargetPath As String = Nothing

        If StrComp(Path.GetExtension(strTargetPath), ".LNK", vbTextCompare) = 0 Then
            Static objShell As Object
            If objShell Is Nothing Then
                objShell = CreateObject("wscript.shell")
            End If

            Dim shortcut As Object
            shortcut = objShell.createshortcut(strTargetPath)

            If File.Exists(shortcut.targetpath) Or Directory.Exists(shortcut.targetpath) Then
                strShortcutTargetPath = shortcut.targetpath
                Console.WriteLine(" -> " & shortcut.targetpath)
            Else
                Console.WriteLine(" *> " & shortcut.targetpath)
            End If
        Else
            Console.WriteLine()
        End If

        If mblnOpenDir Then
            Console.Write("Opening directory ... ")
            If mblnTarget And strShortcutTargetPath IsNot Nothing Then
                ShowDirectory(strShortcutTargetPath)
            Else
                ShowDirectory(strTargetPath)
            End If
        End If

        If mblnOpenProp Then
            Console.Write("Opening properties dialog ... ")
            If mblnTarget And strShortcutTargetPath IsNot Nothing Then
                ShowProperties(strShortcutTargetPath)
            Else
                ShowProperties(strTargetPath)
            End If
        End If
    End Sub

    Private Sub ShowDirectory(ByVal strFilePath As String)
        Shell("explorer.exe /e, /select, " & strFilePath, 1, False)
        Console.WriteLine("success!")
    End Sub

    Const SEE_MASK_INVOKEIDLIST = &HC
    Const SEE_MASK_NOCLOSEPROCESS = &H40
    Const SEE_MASK_FLAG_NO_UI = &H400

    Declare Function ShellExecuteEx Lib "shell32.dll" (ByRef SEI As SHELLEXECUTEINFO) As Integer
    Declare Function GetLastError Lib "kernel32" () As Integer

    Public Structure SHELLEXECUTEINFO
        Dim cbSize As Integer
        Dim fMask As Integer
        Dim hwnd As IntPtr
        Dim lpVerb As String
        Dim lpFile As String
        Dim lpParameters As String
        Dim lpDirectory As String
        Dim nShow As Integer
        Dim hInstApp As IntPtr
        Dim lpIDList As IntPtr
        Dim lpClass As String
        Dim hkeyClass As IntPtr
        Dim dwHotKey As Integer
        Dim hIcon As IntPtr
        Dim hProcess As IntPtr
    End Structure


    Public Sub ShowProperties(ByVal strFilePath As String)
        Dim SEI As SHELLEXECUTEINFO

        With SEI
            .cbSize = Marshal.SizeOf(SEI)
            .fMask = SEE_MASK_INVOKEIDLIST ' SEE_MASK_NOCLOSEPROCESS Or SEE_MASK_INVOKEIDLIST Or SEE_MASK_FLAG_NO_UI
            .lpVerb = "properties"
            .lpFile = strFilePath
        End With

        Dim ret = ShellExecuteEx(SEI)

        ' 如果返回值小于等于32,则表示有错误;
        If ret <> 0 Then
            Console.WriteLine("success!")
        Else
            Console.WriteLine("failed(" & GetLastError() & ")!")
        End If
    End Sub
End Module
